﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Lapkin.Models.DataModels;

namespace Lapkin.Models.Repositories
{
    public class AccountRepository
    {
        private readonly MainContext _db;
        private readonly SqlRepository _sqlRepository;
        public AccountRepository(MainContext db, SqlRepository sqlRepository)
        {
            _sqlRepository = sqlRepository;
            _db = db;
        } 
        public bool CreateRole(Action<Role> init)
        {
            var newRole = new Role
                {
                    Id = Guid.NewGuid(),
                };
            init(newRole);
            try
            {
                _db.Roles.Add(newRole);
                _db.SaveChanges();
                return true;
            }
            catch
            {
                return false;
            }
        }

        public bool UpdateRole(Role role)
        {
            if (role.Id != Guid.Empty)
            {
                _db.Roles.Attach(role);
                _sqlRepository.CheckChange(role);
                _db.Configuration.ValidateOnSaveEnabled = false;
                _db.SaveChanges();
                _db.Configuration.ValidateOnSaveEnabled = true;
                return true;
            }
            return false;
        }

        public Role GetRole(Expression<Func<Role, bool>> query)
        {
            return _db.Roles.FirstOrDefault(query);
        }

        public bool IsUserInRole(string email, string roleName)
        {
            var user = _db.Users.FirstOrDefault(u => u.Email == email);
            if (user != null)
            {
                if (user.Roles.FirstOrDefault(r => r.Name == roleName) != null)
                {
                    return true;
                }
            }
            return false;
        }

        public string[] FindUsersInRole(string roleName)
        {
            var result = new List<string>();
            var role = _db.Roles.FirstOrDefault(r => r.Name == roleName);
            if (role != null)
            {
                result.AddRange(role.Users.Select(u => u.Email));
            }
            return result.ToArray();
        }

        public bool CreateUser(Action<User> init)
        {
            var newUser = new User
                {
                    Id = Guid.NewGuid(),
                    Address = "",
                    IsBanned = false,
                    LastActiveDate = DateTime.Now,
                    Phone = "",
                    RegDate = DateTime.Now
                };
            init(newUser);
            try
            {
                _db.Users.Add(newUser);
                _db.SaveChanges();
                return true;
            }
            catch
            {
                return false;
            }
        }

        public bool UpdateUser(User user)
        {
            if (user.Id != Guid.Empty)
            {
                _db.Users.Attach(user);
                _sqlRepository.CheckChange(user);
                _db.Configuration.ValidateOnSaveEnabled = false;
                _db.SaveChanges();
                _db.Configuration.ValidateOnSaveEnabled = true;
                return true;
            }
            return false;
        }

        public User GetUser(Expression<Func<User, bool>> query)
        {
            return _db.Users.FirstOrDefault(query);
        }

        public bool ValidateUser(string email, string password)
        {
            var user = _db.Users.FirstOrDefault(u => u.Email == email && u.Password == password);
            if (user == null || (user.IsBanned ?? false))
            {
                return false;
            }
            user.LastActiveDate = DateTime.Now;
            UpdateUser(user);
            return true;
        }

        public string[] GetRolesForUser(string email)
        {
            var result = new List<string>();
            var user = _db.Users.FirstOrDefault(u => u.Email == email);
            if (user != null)
            {
                result.AddRange(user.Roles.Select(role => role.Name));
            }
            return result.ToArray();
        }
    }
}